﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using Wicture.DbRESTFul;
using Wicture.DbRESTFul.SQL;
using Wicture.EPC.Common;
using Wicture.EPC.Service.Benz.Enum;
using Wicture.EPC.Service.Benz.Filters;
using Wicture.EPC.Service.Benz.Models;

namespace Wicture.EPC.Service.Benz.Repository
{
    public class EpcRepository : DbRESTFulRepository
    {
        private string[] dictionaryFields = new string[] { "engine", "auto", "manual", "steer", "aBody", "frontax", "reaRax", "DIST", "platFrm", "exhaustSys" };
        /// <summary>
        /// 1、逐级选择车型
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object ModelSelector(Model_SelectorParam param)
        {
            var title = "";
            if (string.IsNullOrEmpty(param.id)) param.id = "0";

            List<Models.ModelSelector> list = new List<Models.ModelSelector>();
            //第一步：选择大类(小轿车、货车等)
            if (param.id == "0")
            {
                title = "选择大类";
                list = (List<ModelSelector>)base.Invoke<ModelSelector>(CSIs.List_Model_Selector_Step1, param);
            }
            //第二步：选择车型
            if (param.route == "step2")
            {
                title = "选择车型";
                list = (List<ModelSelector>)base.Invoke<ModelSelector>(CSIs.List_Model_Selector_Step2, new { carType = param.id });
            }

            var ids = param.id.Split("_");
            //第三步：选择机组
            if (param.route == "step3")
            {
                title = "选择机组";
                list = (List<ModelSelector>)base.Invoke<ModelSelector>(CSIs.List_Model_Selector_Step3, new { carType = ids[1], aggType = ids[0] });
            }

            //第四步：选择市场
            if (param.route == "step4")
            {
                title = "选择市场";
                list = (List<ModelSelector>)base.Invoke<ModelSelector>(CSIs.List_Model_Selector_Step4, new { modelCode = ids[0], carType = ids[1] });
            }
            //第五步：选择市场对应的catNum
            if (param.route == "step5")
            {
                title = "选择目录";
                list = (List<ModelSelector>)base.Invoke<ModelSelector>(CSIs.List_Model_Selector_Step5, new { region = ids[0], modelCode = ids[1], carType = ids[2] });
                foreach (var item in list)
                {
                    if (GetMainGroupForMachineGroup(item.id.Split("_")).Count() > 0) item.route = "step6";
                    else item.route = "step8";
                }
            }

            if (param.route == "step6")
            {
                title = "选择主组";
                list = GetMainGroupForMachineGroup(ids);
                list.AddRange(GetMainGroupForModel(ids));

            }

            if (param.route == "step7")
            {
                title = "选择机组型号";
                list = GetSelectorMachineGroup(ids);
            }

            if (param.route == "step8")
            {
                title = "选择主组";
                list = GetMainGroupForModel(ids);
            }

            if (list.Count() < 1) throw new LogicalException($"参数错误", "612");

            var result = new Model_SelectorResult
            {
                title = title,
                items = list
                   .Select(p => new Model_SelectorResult._items { id = p.id, code = p.code, name = p.name, hasNext = p.hasNext, route = p.route, imageUrl = p.imageUrl })
                   .ToList()
            };
            return result;
        }

        private List<ModelSelector> GetMachineMainGroupForVin(string[] ids, string vin, string brandCode)
        {
            modelDetail modelDetail = base.Invoke<modelDetail>(CSIs.Query_Main_Group_For_Model_Step1, new { catNum = ids[0], modelCode = ids[2] });
            if (modelDetail == null)
            {
                return new List<ModelSelector>();
            }
            VinInfo vinInfo = base.Invoke<VinInfo>(CSIs.Query_Info_For_Vin, new { vin, brandCode });
            Dictionary<string, string> dicModelCode = new Dictionary<string, string>();
            if (!string.IsNullOrEmpty(vinInfo.engine) && vinInfo.engine.Length >= 6)
            {
                var vinEngineCode = vinInfo.engine.Substring(0, 6);
                dicModelCode.Add("M", vinEngineCode);
            }

            if (!string.IsNullOrEmpty(vinInfo.transmission) && vinInfo.transmission.Length >= 6)
            {
                var vinTransCode = vinInfo.transmission.Substring(0, 6);
                var autoCodes = GetModelCodes(modelDetail.auto);
                if (autoCodes.Contains(vinTransCode))
                {
                    dicModelCode.Add("GA", vinTransCode);
                }
                else
                {
                    var manulCodes = GetModelCodes(modelDetail.manual);
                    if (manulCodes.Contains(vinTransCode))
                    {
                        dicModelCode.Add("GM", vinTransCode);
                    }
                }
            }

            var steeringCodes = GetModelCodes(modelDetail.steer);
            if (steeringCodes.Count > 1 && !string.IsNullOrEmpty(vinInfo.steering) && vinInfo.steering.Length >= 6)
            {
                steeringCodes = steeringCodes.Where(q => q == vinInfo.steering.Substring(0, 6)).ToHashSet();
            }
            if (steeringCodes.Count == 1)
            {
                dicModelCode.Add("LG", steeringCodes.First());
            }
            var bodyCodes = GetModelCodes(modelDetail.aBody);
            if (bodyCodes.Count == 1)
            {
                dicModelCode.Add("FH", bodyCodes.First());
            }
            var frontaxCodes = GetModelCodes(modelDetail.frontax);
            if (frontaxCodes.Count > 1 && !string.IsNullOrEmpty(vinInfo.frontAxle1) && vinInfo.frontAxle1.Length >= 6)
            {
                frontaxCodes = steeringCodes.Where(q => q == vinInfo.frontAxle1.Substring(0, 6)).ToHashSet();
            }
            if (frontaxCodes.Count == 1)
            {
                dicModelCode.Add("VA", frontaxCodes.First());
            }

            var reaRaxCodes = GetModelCodes(modelDetail.reaRax);
            if (reaRaxCodes.Count > 1 && !string.IsNullOrEmpty(vinInfo.rearAxle1) && vinInfo.rearAxle1.Length >= 6)
            {
                reaRaxCodes = reaRaxCodes.Where(q => q == vinInfo.rearAxle1.Substring(0, 6)).ToHashSet();
            }
            if (reaRaxCodes.Count == 1)
            {
                dicModelCode.Add("HA", reaRaxCodes.First());
            }

            var DISTCodes = GetModelCodes(modelDetail.DIST);
            if (DISTCodes.Count == 1)
            {
                dicModelCode.Add("VG", DISTCodes.First());
            }

            var platFrmCodes = GetModelCodes(modelDetail.platFrm);
            if (platFrmCodes.Count == 1)
            {
                dicModelCode.Add("P", platFrmCodes.First());
            }

            var exhaustSysCodes = GetModelCodes(modelDetail.exhaustSys);
            if (exhaustSysCodes.Count > 1 && !string.IsNullOrEmpty(vinInfo.exhaustsys) && vinInfo.exhaustsys.Length >= 6)
            {
                exhaustSysCodes = exhaustSysCodes.Where(q => q == vinInfo.exhaustsys.Substring(0, 6)).ToHashSet();
            }
            if (exhaustSysCodes.Count == 1)
            {
                dicModelCode.Add("AS", exhaustSysCodes.First());
            }
            IEnumerable<MainGroupForMachine> machineGroups = base.Invoke<MainGroupForMachine>(CSIs.Query_Main_Group_For_MachineCode, new { modelCodes = dicModelCode.Values.ToList(), modelCode = ids[2] });
            machineGroups = machineGroups.OrderByDescending(q => q.carType);

            List<ModelSelector> retGroups = new List<ModelSelector>();
            foreach (var key in dicModelCode.Keys)
            {
                var modelCode = dicModelCode[key];
                var groups = machineGroups.Where(q => q.modelCode == modelCode);
                retGroups.AddRange(groups.GroupBy(q => q.mainGroupCode).Select(q => q.First()).Select(q => new ModelSelector { code = q.mainGroupCode, hasNext = false, id = q.id, name = $"{q.mainGroupNameZh} (机组 {key})", selectorId = $"{q.catNum}_0_{q.modelCode}_0", imageUrl = q.imageUrl }));
            }
            return retGroups.OrderBy(q => q.code).ToList();
        }

        /// <summary>
        /// 2、查询主组
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryMainGroup(Model_SelectorParam param)
        {
            var ids = param.id.Split("_");
            List<ModelSelector> groups = new List<ModelSelector>();
            if (!string.IsNullOrEmpty(param.vin))
            {
                groups.AddRange(GetMachineMainGroupForVin(ids, param.vin, param.brandCode));
            }
            groups.AddRange(GetMainGroupForModel(ids));
            return groups;
        }



        /// <summary>
        /// 3、查询子组
        /// </summary>  
        /// <param name="param"></param>
        /// <returns></returns>
        public object QuerySubGroup(JObject param)
        {
            param.RemoveEmptyValues();

            string selectorId = param.Value<string>(ParamFields._selectorId);
            string id = param.Value<string>(ParamFields._id);
            var ids = selectorId.Split(SplitFields.UnderLine);

            param["catNum"] = ids[0];
            param["mainGroupCode"] = id.Split(SplitFields.Minus)[0];

            IEnumerable<Query_SubGroupResult> subGroups = base.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup, param);
            foreach (var item in subGroups)
            {
                item.belongTo = true;
            }
            return subGroups;
        }

        /// <summary>
        /// 4、查询零件列表（通过子组或vin码）
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryParts(JObject param)
        {
            param.RemoveEmptyValues();

            string selectorId = param.Value<string>(ParamFields._selectorId);
            var ids = selectorId.Split(SplitFields.UnderLine);
            var mainGroupCode = param.Value<string>("mainGroupId").Split(SplitFields.Minus)[0];

            param["catNum"] = ids[0];
            param["mainGroupCode"] = mainGroupCode;
            param["subGroupCode"] = param["id"];
            if (ids.Length == 7)
            {
                param["submm1"] = ids[1].Substring(3, 3);
            }
            else
            {
                param["submm1"] = ids[2].Substring(3, 3);
            }

            List<Query_PartsResult> result = base.Invoke<Query_PartsResult>(CSIs.Query_Parts, param);

            result = BuildResultForXY(result);

            string vin = param.Value<string>(ParamFields._vin);
            string brandCode = param.Value<string>(ParamFields._brandCode);
            if (!string.IsNullOrEmpty(vin))
            {
                try
                {
                    var vinInfo = base.Invoke(CSIs.Query_Info_For_Vin, new { vin, brandCode });
                    ISet<string> featureCodes = GetVinFeatureCodes(GetFeatureCodesStr(vinInfo));

                    string chassis = vin.Substring(vin.Length - 6, 6);
                    List<FootNote> footNotes = base.Invoke<FootNote>(CSIs.Query_Footnotes, new { catNum = param.Value<string>("catNum"), groupNums = new string[] { param.Value<string>("mainGroupCode") } });
                    var dicFootNotes = footNotes.GroupBy(q => q.FtntNum).ToDictionary(k => k.Key, v => v.ToList());
                    foreach (var item in result)
                    {
                        VinFilter.FilterResult(item, featureCodes, dicFootNotes, chassis, vinInfo);
                    }
                    BuildResultForSpring(result, vinInfo);
                    BuildResultForSaCodeCount(result);
                }
                catch (Exception ex)
                {
                    LoggerManager.Logger.LogError(ex, "Vin Filter Error!");
                }
            }
            return result;
        }

        private ISet<string> GetVinFeatureCodes(string featureStr)
        {
            ISet<string> retSet = new HashSet<string>();
            if (!string.IsNullOrEmpty(featureStr))
            {
                for (int j = 0; j < featureStr.Length; j += 4)
                {
                    if (j + 4 > featureStr.Length) //最后的code不足4位的情况进行取模
                    {
                        retSet.Add(featureStr.Substring(j, featureStr.Length % 4).Trim());
                    }
                    else
                    {
                        retSet.Add(featureStr.Substring(j, 4).Trim());
                    }
                }
            }
            return retSet;
        }
        /// <summary>
        /// 查询VIN下所有配件
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryAllPartsByVin(DbRESTFulRepository repository, JObject param)
        {
            param.RemoveEmptyValues();

            string vin = param.Value<string>(ParamFields._vin);
            string brandCode = param.Value<string>(ParamFields._brandCode);
            List<Query_PartsResult> result = base.Invoke<Query_PartsResult>(CSIs.Query_Parts, param);
            if (!string.IsNullOrEmpty(vin))
            {
                try
                {
                    var vinInfo = base.Invoke(CSIs.Query_Info_For_Vin, new { vin, brandCode });
                    ISet<string> featureCodes = GetVinFeatureCodes(GetFeatureCodesStr(vinInfo));

                    string chassis = vin.Substring(vin.Length - 6, 6);
                    List<FootNote> footNotes = base.Invoke<FootNote>(CSIs.Query_Footnotes, new { catNum = param.Value<string>("catNum"), groupNums = new string[] { param.Value<string>("mainGroupCode") } });
                    var dicFootNotes = footNotes.GroupBy(q => q.FtntNum).ToDictionary(k => k.Key, v => v.ToList());
                    foreach (var item in result)
                    {
                        VinFilter.FilterResult(item, featureCodes, dicFootNotes, chassis, vinInfo);
                    }
                    BuildResultForSpring(result, vinInfo);
                    BuildResultForSaCodeCount(result);
                }
                catch (Exception ex)
                {
                    LoggerManager.Logger.LogError(ex, "Vin Filter Error!");
                }
            }
            return result;
        }

        private void BuildResultForSpring(List<Query_PartsResult> result, dynamic vinInfo)
        {
            ISet<string> springParts = GetSpringPartsByVinInfo(vinInfo);
            var springSNs = result.Where(q => q.belongToVin && springParts.Contains(q.partCode)).Select(q => q.imageSN).ToHashSet();
            if (!springSNs.Any())
            {
                return;
            }
            foreach (var item in result)
            {
                if (springSNs.Contains(item.imageSN))
                {
                    if (!springParts.Contains(item.partCode))
                    {
                        item.belongToVin = false;
                    }
                }
            }
        }

        private ISet<string> GetSpringPartsByVinInfo(dynamic vinInfo)
        {
            List<string> springParts = new List<string>();
            if (!string.IsNullOrEmpty(vinInfo.frontSpringStrut))
            {
                springParts.AddRange(vinInfo.frontSpringStrut.Split(','));
            }
            if (!string.IsNullOrEmpty(vinInfo.frontSpring))
            {
                springParts.AddRange(vinInfo.frontSpring.Split(','));
            }
            if (!string.IsNullOrEmpty(vinInfo.rearSpring))
            {
                springParts.AddRange(vinInfo.rearSpring.Split(','));
            }
            if (!string.IsNullOrEmpty(vinInfo.rearSpringSuppl))
            {
                springParts.AddRange(vinInfo.rearSpringSuppl.Split(','));
            }
            return springParts.Where(x => !string.IsNullOrEmpty(x)).ToHashSet();
        }

        /// <summary>
        /// EPC内零件搜索
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object SearchParts(JObject param)
        {
            param.RemoveEmptyValues();
            var selectorId = param.Value<string>("selectorId");
            var ids = selectorId.Split('_');
            var catNum = ids[0];
            var subMods = "";
            if (ids.Length == 7)
            {
                subMods = ids[1].Substring(3, 3);
            }
            else
            {
                subMods = ids[2].Substring(3, 3);
            }
            var partCodes = param.Value<string>("partCodes");
            var brandCode = param.Value<string>("brandCode");
            List<SearchSubGroupResults> searchResults = base.Invoke<SearchSubGroupResults>(CSIs.Search_SubGroups_By_PartCodes, new { brandCode, partCodes = partCodes.Split(','), catNum, subMods });
            List<Query_MainGroupResult> mainGroups = searchResults.Select(q => new { q.mainGroupCode, q.mainGroupName }).Distinct().Select(x => new Query_MainGroupResult { id = x.mainGroupCode, code = x.mainGroupCode, name = x.mainGroupName, isBelongTo = true }).ToList();
            List<Query_SubGroupResult> subGroups = searchResults.GroupBy(q => new { q.mainGroupCode, q.subGroupCode }).Select(x => new Query_SubGroupResult { code = x.Key.subGroupCode, belongTo = true, imageSN = x.Key.subGroupCode, imageUrl = x.First().imageUrl, mainGroupCode = x.Key.mainGroupCode, mainGroupId = x.Key.mainGroupCode, name = x.First().subGroupName, id = x.Key.subGroupCode }).ToList();
            return new SearchPartsResult { mainGroups = mainGroups, subGroups = subGroups };
        }

        private void BuildResultForSaCodeCount(List<Query_PartsResult> result)
        {
            var infos = result.Where(x => x.belongToVin).GroupBy(x => new { x.imageSN, x.posAddr }).Select(x => new { SaCodeCount = x.Max(y => y.saCodeCount), SN = x.Key });
            var notBelongs = (from r in result
                              join
                              i in infos on new { r.imageSN, r.posAddr } equals i.SN
                              where r.belongToVin && r.saCodeCount < i.SaCodeCount
                              select r);
            notBelongs.ForEach(x => x.belongToVin = false);
        }
        private void BuildResultForSaCodeCount(List<PartCatalogResult> result)
        {
            var infos = result.Where(x => x.belongToVin).GroupBy(x => new { x.subGroupCode, x.imageSN, x.posAddr }).Select(x => new { SaCodeCount = x.Max(y => y.saCodeCount), SN = x.Key });
            var notBelongs = (from r in result
                              join
                              i in infos on new { r.subGroupCode, r.imageSN, r.posAddr } equals i.SN
                              where r.belongToVin && r.saCodeCount < i.SaCodeCount
                              select r);
            notBelongs.ForEach(x => x.belongToVin = false);
        }

        private List<Query_PartsResult> BuildResultForXY(List<Query_PartsResult> result)
        {
            result = result.Where(x => !x.partCode.Equals("XXXXXXXXXXXXX")).ToList();
            for (int i = 0; i < result.Count; i++)
            {
                if (result[i].partCode.Equals("YYYYYYYYYYYYY"))
                {
                    if (i > 0)
                    {
                        result[i - 1].codeB += result[i].codeB;
                        result[i - 1].footNotes += result[i].footNotes;
                    }
                    result.RemoveAt(i);
                    i--;
                }
            }
            return result;
        }

        /// <summary>
        /// 5、获取配件详情
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryPartDetail(JObject param)
        {
            param.RemoveEmptyValues();
            var selectorId = param.Value<string>(ParamFields._selectorId);
            var partId = param.Value<string>(ParamFields._partId);
            string mainGroupCode = param.Value<string>("mainGroupId")?.Split(SplitFields.Minus)[0];
            if (!string.IsNullOrEmpty(selectorId))
            {
                var ids = selectorId.Split('_');
                param["catNum"] = ids[0];
                param["mainGroupCode"] = mainGroupCode;
                param["subGroupCode"] = param["subGroupId"];
                if (ids.Length == 7)
                {
                    param["submm1"] = ids[1].Substring(3, 3);
                }
                else
                {
                    param["submm1"] = ids[2].Substring(3, 3);
                }
            }

            dynamic data = null;
            if (string.IsNullOrEmpty(partId))
            {
                data = base.Invoke(CSIs.Get_Part_Detail, param);
            }
            else
            {
                data = base.Invoke(CSIs.Get_Usage_Detail, param);
            }

            if (data == null) return null;
            // 1、基本信息赋值
            Query_Part_DetailResult result = JObject.FromObject(data).ToObject<Query_Part_DetailResult>();
            //3.替换件处理
            if (!string.IsNullOrEmpty(result.replacementPartNo))
            {
                List<Part> supersessions = base.Invoke<Part>(CSIs.Query_Part_By_Codes, new { partCodes = result.replacementPartNo.Split(',') });
                var replacements = new List<Query_Part_DetailResult._replacements>();
                var brandCode = param.Value<string>("brandCode");
                var brandName = BrandDictionary.GetName(brandCode);
                replacements.AddRange(supersessions.Select(q => new Query_Part_DetailResult._replacements
                {
                    brandCode = brandCode,
                    brandName = brandName,
                    partCode = q.partCode,
                    partName = q.partName,
                    cost = q.cost,
                    price = q.price,
                    priceUpdatedAt = q.priceUpdatedAt,
                    stock = q.stock
                }));
                result.replacements = replacements;
            }

            //4.配件附加属性处理
            var props = new List<Query_Part_DetailResult._props>
            {
                new Query_Part_DetailResult._props { key = "英文名", value = result.partNameEn ?? string.Empty },
                new Query_Part_DetailResult._props { key = "件数", value = result.quantity ?? string.Empty },
                new Query_Part_DetailResult._props { key = "备注", value = result.remark ?? string.Empty }
            };
            result.props = props.Where(q => !string.IsNullOrEmpty(q.value)).ToList();
            return result;
        }


        /// <summary>
        /// 6.查询热点信息
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryHotPoints(JObject param)
        {
            var selectorId = param.Value<string>(ParamFields._selectorId);
            var ids = selectorId.Split(SplitFields.UnderLine);
            string mainGroupCode = param.Value<string>("mainGroupId")?.Split(SplitFields.Minus)[0];
            param["catNum"] = ids[0];
            param["mainGroupCode"] = mainGroupCode;
            param["subGroupCode"] = param["id"];

            IEnumerable<HotPoint> data = base.Invoke<HotPoint>(CSIs.Query_HotPoints, param);
            if (data.Count() == 0) return null;
            var hotPointGroup = data.GroupBy(e => e.url);

            var imgs = new List<Query_HotPointsResult._imgs>();
            foreach (var item in hotPointGroup)
            {
                imgs.Add(new Query_HotPointsResult._imgs
                {
                    url = item.Key,
                    points = (from n in item
                              select new Query_HotPointsResult._imgs._points
                              {
                                  sn = n.sn,
                                  x = n.x,
                                  y = n.y,
                                  w = n.w,
                                  h = n.h
                              }).ToList()

                });
            }
            return new { imgs };
        }

        /// <summary>
        /// 7.指定车型的详细信息
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QueryModel(JObject request)
        {
            Get_Model_InfoParam param = request.ToObject<Get_Model_InfoParam>();

            Get_Model_InfoResult result = new Get_Model_InfoResult();
            string featureCodesStr = null;
            string type = null;
            dynamic vin = null;
            if (!string.IsNullOrEmpty(param.vin))
            {
                if (param.vin.Length == 8)
                {
                    var vins = base.Invoke(CSIs.Query_vin_for_vin8, param);
                    Get_Model_InfoResult vinsModel = JObject.FromObject(vins).ToObject<Get_Model_InfoResult>();
                    if (vinsModel.vins == null || vinsModel.vins.Count == 0)
                    {
                        throw new LogicalException($"未找到该vin码(BENZ):{param.vin}", 610);
                    }
                    else if (vinsModel.vins.Count == 1)
                    {
                        param.vin = vinsModel.vins[0].vin;
                    }
                    else
                    {
                        return vinsModel;
                    }
                }
                vin = base.Invoke(CSIs.Query_Info_For_Vin, param);
                if (vin == null)
                {
                    throw new LogicalException($"未找到该vin码(BENZ):{param.vin}", 610);
                }
                string vinCode = vin.vin;

                featureCodesStr = GetFeatureCodesStr(vin);
                type = vin.type;
                result = JObject.FromObject(vin).ToObject<Get_Model_InfoResult>();
                var props = new List<Get_Model_InfoResult._props> {
                        new Get_Model_InfoResult._props{ key="车架号",value = vinCode},
                    };
                if (!string.IsNullOrEmpty(vin.name))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "车型", value = vin.name });
                }
                if (!string.IsNullOrEmpty(vin.transmission))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "变速箱", value = vin.transmission });
                }
                if (!string.IsNullOrEmpty(vin.engine))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "发动机", value = vin.engine });
                }
                if (!string.IsNullOrEmpty(vin.orderNum1))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "生产订单编号", value = vin.orderNum1 });
                }
                if (!string.IsNullOrEmpty(vin.releaseDate))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "生产日期", value = vin.releaseDate });
                }
                if (!string.IsNullOrEmpty(vin.deliveryDate))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "交货日期", value = vin.deliveryDate });
                }
                if (!string.IsNullOrEmpty(vin.frontAxle1))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "前轴", value = vin.frontAxle1 });
                }
                if (!string.IsNullOrEmpty(vin.frontAxle2))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "前轴2", value = vin.frontAxle2 });
                }
                if (!string.IsNullOrEmpty(vin.rearAxle1))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "后轴", value = vin.rearAxle1 });
                }
                if (!string.IsNullOrEmpty(vin.rearAxle2))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "后轴2", value = vin.rearAxle2 });
                }
                if (!string.IsNullOrEmpty(vin.steering))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "转向系统", value = vin.steering });
                }
                if (!string.IsNullOrEmpty(vin.bodyCode))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "车身", value = vin.bodyCode });
                }
                if (!string.IsNullOrEmpty(vin.lights))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "照明", value = vin.lights });
                }
                if (!string.IsNullOrEmpty(vin.frontSpringStrut))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "前悬架滑柱", value = vin.frontSpringStrut });
                }
                if (!string.IsNullOrEmpty(vin.frontSpring))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "前部弹簧", value = vin.frontSpring });
                }
                if (!string.IsNullOrEmpty(vin.rearSpring))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "后部弹簧", value = vin.rearSpring });
                }
                if (!string.IsNullOrEmpty(vin.rearSpringSuppl))
                {
                    props.Add(new Get_Model_InfoResult._props { key = "后部垫片", value = vin.rearSpringSuppl });
                }
                result.props = props;

            }
            else
            {
                var ids = param.id.Split("_");
                var model = base.Invoke(CSIs.Get_Model, new { param.brandCode, catNum = ids[0], modelCode = ids[1] });
                if (model != null)
                {
                    featureCodesStr = model.featureCodes;
                    result = JObject.FromObject(model).ToObject<Get_Model_InfoResult>();
                }
            }

            if (!string.IsNullOrEmpty(featureCodesStr))
            {
                HashSet<string> featureCodes = new HashSet<string>();
                //便于截取，在最后加一个空格
                if (featureCodesStr.Length % 4 != 0)
                {
                    featureCodesStr += " ";
                }
                for (int j = 0; j < featureCodesStr.Length; j += 4)
                {
                    featureCodes.Add(featureCodesStr.Substring(j, 4).Trim());
                }
                IEnumerable<Feature> vinFeatures = base.Invoke<Feature>(CSIs.Query_Vin_Features, new { featureCodes, type });
                vinFeatures = vinFeatures.GroupBy(q => q.featureCode).Select(q => q.First()).OrderBy(e => e.featureCode);
                result.features = vinFeatures.Select(f => new Get_Model_InfoResult._features() { key = f.featureCode, value = f.description }).ToList();
            }

            if (vin != null)
            {
                if (!string.IsNullOrEmpty(vin.paint1))
                {
                    var paint = result.features.Where(q => q.key == vin.paint1).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "油漆代码1", value = $"{vin.paint1} {paint.value}" });
                    }
                }
                if (!string.IsNullOrEmpty(vin.paint2))
                {
                    var paint = result.features.Where(q => q.key == vin.paint2).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "油漆代码2", value = $"{vin.paint2} {paint.value}" });
                    }
                }
                if (!string.IsNullOrEmpty(vin.paint3))
                {
                    var paint = result.features.Where(q => q.key == vin.paint3).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "油漆代码3", value = $"{vin.paint3} {paint.value}" });
                    }
                }
                if (!string.IsNullOrEmpty(vin.paint4))
                {
                    var paint = result.features.Where(q => q.key == vin.paint4).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "油漆代码4", value = $"{vin.paint4} {paint.value}" });
                    }
                }
                if (!string.IsNullOrEmpty(vin.paint5))
                {
                    var paint = result.features.Where(q => q.key == vin.paint5).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "油漆代码1", value = $"{vin.paint5} {paint.value}" });
                    }
                }
                if (!string.IsNullOrEmpty(vin.interior))
                {
                    var paint = result.features.Where(q => q.key == vin.interior).FirstOrDefault();
                    if (paint != null)
                    {
                        result.props.Add(new Get_Model_InfoResult._props { key = "装备", value = $"{vin.interior} {paint.value}" });
                    }
                }


            }
            return result;
        }

        private string GetFeatureCodesStr(dynamic vin)
        {
            StringBuilder sb = new StringBuilder(vin.featureCodes);
            if (vin.featureCodes.Length % 4 != 0)
            {
                sb.Append(" ");
            }
            sb.Append(GetFeatureCodeStr(vin.paint1))
            .Append(GetFeatureCodeStr(vin.paint2))
            .Append(GetFeatureCodeStr(vin.paint3))
            .Append(GetFeatureCodeStr(vin.paint4))
            .Append(GetFeatureCodeStr(vin.paint5))
            .Append(GetFeatureCodeStr(vin.interior));
            return sb.ToString();
        }
        private string GetFeatureCodeStr(string code)
        {
            if (code == null)
            {
                return "";
            }
            else if (code.Length == 3)
            {
                return code + " ";
            }
            else if (code.Length == 4)
            {
                return code;
            }
            return "";
        }

        /// <summary>
        /// 获取面包屑导航栏
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object GetCrumbs(JObject param)
        {
            var brandCode = param.Value<string>(ParamFields._brandCode);
            var route = param.Value<string>(ParamFields._route);
            var id = param.Value<string>(ParamFields._id);
            var vin = param.Value<string>(ParamFields._vin);
            var selectorId = param.Value<string>(ParamFields._selectorId);
            var mainGroupId = param.Value<string>("mainGroupId");
            List<Query_CrumbResult> result = new List<Query_CrumbResult>();
            switch (route)
            {
                case "step2":
                    GetCrumbsByStep2(brandCode, id, result);
                    break;
                case "step3":
                    GetCrumbsByStep3(brandCode, id, result);
                    break;
                case "step4":
                    GetCrumbsByStep4(brandCode, id, result);
                    break;
                case "step5":
                    GetCrumbsByStep5(brandCode, id, result);
                    break;
                case "step6":
                    GetCrumbsByStep6(brandCode, id, result);
                    break;
                case "step7":
                    GetCrumbsByStep7(brandCode, id, result);
                    break;
                case "step8":
                    GetCrumbsByStep8(brandCode, id, result);
                    break;
                case "mainGroup":
                    GetCrumbsByMainGroup(brandCode, id, selectorId, result, string.IsNullOrEmpty(vin));
                    break;
                case "subGroup":
                    GetCrumbsBySubGroup(brandCode, id, mainGroupId, selectorId, result, string.IsNullOrEmpty(vin));
                    break;
                case "catalog":
                    GetCrumbsByCatalog(brandCode, id, result, string.IsNullOrEmpty(vin));
                    break;
                default:
                    break;
            }

            if (string.IsNullOrEmpty(vin))
            {
                result.Add(new Query_CrumbResult { code = brandCode, name = BrandDictionary.GetName(brandCode), step = 0, fieldCode = ParamFields._brandCode, fieldName = "选择品牌" });
            }
            result.Reverse();
            for (int i = 0; i < result.Count; i++)
            {
                result[i].step = i;
            }
            return result;
        }

        public object QueryMaintainParts(JObject param)
        {
            string vinCode = param.Value<string>(ParamFields._vin);
            string brandCode = param.Value<string>(ParamFields._brandCode);
            string selectorId = param.Value<string>(ParamFields._selectorId);
            var vinInfo = base.Invoke(CSIs.Query_Info_For_Vin, new { vin = vinCode, brandCode });
            string[] selectArray = selectorId.Split('_');
            string catNum = selectArray[0];
            string modelCode = selectArray[2];
            string type = modelCode.Substring(0, 3);
            string subMod = modelCode.Substring(3, 3);

            string engine = vinInfo.engine;
            string transmission = vinInfo.transmission;
            string rearAxle = vinInfo.rearAxle1;
            string frontAxle = vinInfo.frontAxle1;

            string engineCode = engine?.Split(' ').FirstOrDefault();
            string transmissionCode = transmission?.Split(' ').FirstOrDefault();
            string rearAxleCode = rearAxle?.Split(' ').FirstOrDefault();
            string frontAxleCode = frontAxle?.Split(' ').FirstOrDefault();
            List<string> modelCodes = new List<string> { modelCode, engineCode, transmissionCode, rearAxleCode, frontAxleCode };
            modelCodes = modelCodes.Where(q => !string.IsNullOrEmpty(q)).ToList();
            List<PartCatalogResult> partCatalogResults = this.Invoke<PartCatalogResult>(CSIs.Query_Part_Catalog, new { modelCode, modelCodes });
            if (!partCatalogResults.Any()) return null;

            string chassis = vinCode.Substring(vinCode.Length - 6, 6);

            ISet<string> featureCodes = GetVinFeatureCodes(GetFeatureCodesStr(vinInfo));

            List<string> footNoteNos = new List<string>();
            List<FootNote> footNotes = new List<FootNote>();
            foreach (var partCatalogResult in partCatalogResults)
            {
                footNoteNos.AddRange(VinFilter.GetFintnumList(partCatalogResult.footNotes));
            }
            footNoteNos = footNoteNos.Distinct().ToList();
            if (footNoteNos.Any())
            {
                footNotes = base.Invoke<FootNote>(CSIs.Query_Footnotes2, new { catNums = partCatalogResults.Select(q => q.catNum).Distinct(), groupNums = partCatalogResults.Select(q => q.mainGroupCode).Distinct(), fintNums = footNoteNos });
            }
            var groups = partCatalogResults.GroupBy(q => new { q.catNum, q.mainGroupCode });
            foreach (var group in groups)
            {
                var dicFootNotes = footNotes.Where(q => q.catNum == group.Key.catNum && q.groupNum == group.Key.mainGroupCode).GroupBy(q => q.FtntNum).ToDictionary(k => k.Key, v => v.ToList());
                foreach (var item in group)
                {
                    VinFilter.FilterResult(item, featureCodes, dicFootNotes, chassis, vinInfo);
                }
            }
            BuildResultForSaCodeCount(partCatalogResults);
            partCatalogResults = partCatalogResults.Where(q => q.belongToVin).ToList();
            var hotPointsModel = this.Invoke(CSIs.Query_HotPoints_By_Part, new { brandCode, partIds = partCatalogResults.Select(q => q.id).Distinct() });
            JArray allPoints = JArray.FromObject(hotPointsModel);

            foreach (var item in partCatalogResults)
            {
                //2.1适用车型多张图片处理
                var imgs = allPoints.Where(p => p.Value<string>("partId") == item.id).Select(p => p.Value<string>("url")).Distinct().Select(x => new _imgs { url = x }).ToList();
                foreach (var img in imgs)
                {
                    //2.1.1适用车型每张图片对应的热点处理
                    img.points = allPoints.Where(p => p.Value<string>("url") == img.url && p.Value<string>("partId") == item.id)
                                       .Select(p => p.ToObject<_imgs._points>()).ToList();
                }
                item.imgs = imgs.Where(p => p.points.Any(x => !string.IsNullOrEmpty(x.sn))).ToList();
            }
            return BuildPartCatalogList(partCatalogResults);
        }


        private List<PartCatalog> BuildPartCatalogList(List<PartCatalogResult> partCatalogResults)
        {
            List<PartCatalog> retList = new List<PartCatalog>();
            var dic = partCatalogResults.GroupBy(x => x.partCode).ToDictionary(k => k.Key, v => v.ToList());
            foreach (var partCode in dic.Keys)
            {

                var list = dic[partCode];
                var first = list.First();
                PartCatalog info = new PartCatalog()
                {
                    partCode = partCode,
                    partName = first.partName,
                    price = first.price,
                    cost = first.cost,
                    priceUpdatedAt = first.priceUpdatedAt,
                    replacedPartCodes = first.replacedPartCodes,
                    standardCode = first.standardCode,
                    standardName = first.standardName
                };

                info.groups = list.GroupBy(x => new { x.imageSN, x.mainGroupCode, x.mainGroupId, x.mainGroupName, x.catNum, x.modelCode, x.subGroupId, x.subGroupName, x.subGroupCode, x.sn }).Select(q => new PartCatalog._group
                {
                    partId = q.Min(p => p.id),
                    imageSN = q.Key.imageSN,
                    mainGroupCode = q.Key.mainGroupCode,
                    mainGroupId = q.Key.mainGroupId,
                    mainGroupName = q.Key.mainGroupName,
                    selectorId = $"{q.Key.catNum}_0_{q.Key.modelCode}_0",
                    subGroupCode = q.Key.subGroupCode,
                    subGroupId = q.Key.subGroupId.ToString(),
                    subGroupName = q.Key.subGroupName,
                    imgs = q.First().imgs,
                    sn = q.Key.sn
                }).ToList();
                retList.Add(info);
            }

            return retList;
        }

        public object QueryFitModels(JObject param)
        {
            var pageIndex = param.Value<int>(ParamFields._pageIndex);
            var pageSize = 20;
            var brandCode = param.Value<string>(ParamFields._brandCode);
            var partCode = param.Value<string>(ParamFields._partCode);
            var pageStart = (pageIndex + 1) * pageSize + 1;
            var model = base.Invoke(CSIs.Query_Models_By_Part, new { pageIndex, pageStart, pageSize, brandCode, partCode });
            Query_FitModelsResult result = JObject.FromObject(model).ToObject<Query_FitModelsResult>();
            if (result == null || result.items == null || !result.items.Any())
            {
                return result;
            }
            var hotPointsModel = base.Invoke(CSIs.Query_HotPoints_By_Part, new { brandCode, partIds = result.items.Select(q => q.partId).Distinct() });
            JArray allPoints = JArray.FromObject(hotPointsModel);

            foreach (var item in result.items)
            {
                //2.1适用车型多张图片处理
                var imgs = allPoints.Where(p => p.Value<string>(ParamFields._partId) == item.partId).Select(p => p.ToObject<Query_FitModelsResult._models._imgs>()).GroupBy(q => new { q.partId, q.url }).Select(q => new Query_FitModelsResult._models._imgs { partId = q.Key.partId, url = q.Key.url }).ToList();
                foreach (var img in imgs)
                {
                    //2.1.1适用车型每张图片对应的热点处理
                    img.points = allPoints.Where(p => p.Value<string>("url") == img.url && p.Value<string>(ParamFields._partId) == img.partId)
                                       .Select(p => p.ToObject<Query_FitModelsResult._models._imgs._points>()).ToList();
                }
                item.imgs = imgs.Where(p => p.points.Any(x => !string.IsNullOrEmpty(x.sn))).ToList();
                item.imageUrl = item.imgs.FirstOrDefault()?.url;
            }
            return result;
        }

        private void GetCrumbsByCatalog(string brandCode, string id, List<Query_CrumbResult> result, bool withoutVin)
        {
            if (withoutVin)
            {
                GetCrumbsByStep8(brandCode, id, result);
            }
        }

        private void GetCrumbsBySubGroup(string brandCode, string subGroupId, string mainGroupId, string selectorId, List<Query_CrumbResult> result, bool withoutVin)
        {
            var ids = selectorId.Split(SplitFields.UnderLine);
            MainAndSubGroup group = base.Invoke<MainAndSubGroup>(CSIs.Query_SubGroup_Single, new { subGroupCode = subGroupId, mainGroupCode = mainGroupId?.Split(SplitFields.Minus)[0], catNum = ids[0] });
            Query_CrumbResult stepSubGroup = new Query_CrumbResult() { code = group.subGroupCode, fieldCode = "subGroup", fieldName = "选择分组", name = group.subGroupNameZh, id = group.subGroupCode, route = "subGroup", selectorId = selectorId };
            result.Add(stepSubGroup);
            Query_CrumbResult stepMainGroup = new Query_CrumbResult() { code = group.mainGroupCode, fieldCode = "mainGroup", fieldName = "选择主组", name = group.mainGroupNameZh, id = mainGroupId, route = "mainGroup", selectorId = selectorId };
            result.Add(stepMainGroup);
            if (withoutVin)
            {
                GetCrumbsByStep8(brandCode, selectorId, result);
            }
        }

        private void GetCrumbsByMainGroup(string brandCode, string mainGroupId, string selectorId, List<Query_CrumbResult> result, bool withoutVin)
        {
            var ids = selectorId.Split(SplitFields.UnderLine);
            MainGroup mainGroup = base.Invoke<MainGroup>(CSIs.Query_MainGroup_Single, new { mainGroupCode = mainGroupId?.Split(SplitFields.Minus)[0], catNum = ids[0] });
            if (mainGroup != null)
            {
                Query_CrumbResult step = new Query_CrumbResult() { code = mainGroup.mainGroupCode, fieldCode = "mainGroup", fieldName = "选择主组", name = mainGroup.mainGroupNameZh, id = mainGroup.id, route = "mainGroup", selectorId = selectorId };
                result.Add(step);
            }
            if (withoutVin)
            {
                GetCrumbsByStep8(brandCode, selectorId, result);
            }
        }

        private void GetCrumbsByStep2(string brandCode, string id, List<Query_CrumbResult> result)
        {
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step2, new { id, brandCode });
            result.Add(step);
        }

        private void GetCrumbsByStep3(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step3, new { id, code = ids[0], brandCode });
            result.Add(step);
            GetCrumbsByStep2(brandCode, ids[1], result);

        }

        private void GetCrumbsByStep4(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            var modelCode = ids[0];
            var carType = ids[1];
            ModelEntry modelEntry = base.Invoke<ModelEntry>(CSIs.Query_Model_Entry, new { modelCode, carType });
            if (modelEntry.aggType != "FG")
            {
                Query_CrumbResult step = new Query_CrumbResult { code = modelCode, id = id, fieldCode = "series", fieldName = "选择机组", name = modelEntry.seriesName, route = "step4" };
                result.Add(step);
                GetCrumbsByStep3(brandCode, modelEntry.aggType + SplitFields.UnderLine + modelEntry.carType, result);
            }
            else
            {
                Query_CrumbResult step = new Query_CrumbResult { code = modelCode, id = id, fieldCode = "series", fieldName = "选择车型", name = modelEntry.seriesName, route = "step4" };
                result.Add(step);
                GetCrumbsByStep2(brandCode, modelEntry.carType, result);
            }
        }
        private void GetCrumbsByStep5(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step5, new { id, code = ids[0], brandCode });
            result.Add(step);
            GetCrumbsByStep4(brandCode, string.Join(SplitFields.UnderLine, ids, 1, ids.Length - 1), result);
        }
        private void GetCrumbsByStep6(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step6, new { id, catNum = ids[0], modelCode = ids[2] });
            ModelEntry modelEntry = base.Invoke<ModelEntry>(CSIs.Query_Model_Entry, new { modelCode = ids[2], carType = ids[3] });
            if (modelEntry.aggType != "FG")
            {
                step.route = "step8";
            }
            result.Add(step);
            GetCrumbsByStep5(brandCode, string.Join(SplitFields.UnderLine, ids, 1, ids.Length - 1), result);
        }
        private void GetCrumbsByStep7(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step7, new { id, field = ids[0] });
            result.Add(step);
            GetCrumbsByStep6(brandCode, string.Join(SplitFields.UnderLine, ids, 1, ids.Length - 1), result);
        }
        private void GetCrumbsByStep8(string brandCode, string id, List<Query_CrumbResult> result)
        {
            var ids = id.Split(SplitFields.UnderLine);
            if (ids.Length < 7)
            {
                GetCrumbsByStep6(brandCode, id, result);
                return;
            }
            Query_CrumbResult step = base.Invoke<Query_CrumbResult>(CSIs.Get_Crumbs_For_Step8, new { id, catNum = ids[0], modelCode = ids[1] });
            result.Add(step);
            GetCrumbsByStep7(brandCode, string.Join(SplitFields.UnderLine, ids, 2, ids.Length - 2), result);
        }


        #region private mothods

        #region 根据操作环节筛选零件数据（年份、车系等）
        private List<Query_PartsResult> QueryPartsExtend(List<Query_PartsResult> result, JToken param)
        {
            var selector = base.Invoke(CSIs.Get_Model_Selector, new { id = param.Value<int>("selectorId") });
            if (selector.filedName == ModelSelectorRouteEnum.year.ToString())
            {
                var selectorYear = int.Parse(selector.objectCode);
                if (selectorYear > 0)
                {
                    result = result.Where(e => (e.firstYear <= selectorYear && e.lastYear >= selectorYear) || (e.firstYear == null || e.lastYear == null)).ToList();
                }
            }

            if (selector.parentId > 0)
            {
                param["selectorId"] = selector.parentId;
                result = QueryPartsExtend(result, param);
            }
            return result;
        }
        #endregion

        //查询机组的主组数据
        private IEnumerable<ModelSelector> GetMGroup(string id, string catNum, string modelCode, List<string> fields)
        {
            IEnumerable<ModelSelector> list = base.Invoke<ModelSelector>(CSIs.Query_Main_Group_For_Model_Step2, new { id, modelCode, catNum, fields });
            return list;
        }

        private List<ModelSelector> GetSelectorMachineGroup(string[] ids)
        {
            var modelDetail = base.InvokeCode($"select `{ids[0]}` as fieldValue from model_detail where catNum=@catNum and modelCode=@modelCode;", new { catNum = ids[1], modelCode = ids[3] }, true, false, false);
            string id = string.Join(SplitFields.UnderLine, ids);
            string fieldValue = modelDetail.fieldValue;
            List<string> modelCodes = new List<string>();
            //处理字符串
            fieldValue = fieldValue.Replace(" ", "").Replace(",", "");
            if (fieldValue.Length <= 7)
            {
                modelCodes.Add(fieldValue.Replace(".", ""));
            }
            else
            {
                GetModelCodes(modelCodes, fieldValue);
            }
            return base.Invoke<ModelSelector>(CSIs.Query_Main_Group_For_Model_Step5, new { modelCodes, id });
        }

        private List<ModelSelector> GetMainGroupForModel(string[] ids)
        {
            List<ModelSelector> result = new List<ModelSelector>();
            string id, catNum, mainGroupId = null;
            if (ids[0].Length == 2)
            {
                mainGroupId = ids[0];
                catNum = ids[1];
                id = string.Join(SplitFields.UnderLine, ids, 1, ids.Length - 1);

            }
            else
            {
                id = string.Join(SplitFields.UnderLine, ids);
                catNum = ids[0];
            }
            List<ModelSelector> list = base.Invoke<ModelSelector>(CSIs.Query_Main_Group_For_Model_Step4, new { catNum, id });
            if (list.Count() > 0)
            {
                if (mainGroupId != null)
                {
                    foreach (var item in list)
                    {
                        if (item.id == mainGroupId) { item.isSelected = true; break; };
                    }
                }
                else
                {
                    list[0].isSelected = true;
                }
            }
            return list;
        }

        private List<ModelSelector> GetMainGroupForMachineGroup(string[] ids)
        {
            List<ModelSelector> result = new List<ModelSelector>();
            //查询机组数据
            modelDetail modelDetail = base.Invoke<modelDetail>(CSIs.Query_Main_Group_For_Model_Step1, new { catNum = ids[0], modelCode = ids[2] });
            if (modelDetail != null)
            {
                List<string> fields = new List<string>();
                foreach (System.Reflection.PropertyInfo p in modelDetail.GetType().GetProperties())
                {
                    if (dictionaryFields.Contains(p.Name) && p.GetValue(modelDetail) != null) fields.Add(p.Name);
                }
                if (fields.Count() > 0) result.AddRange(GetMGroup(string.Join('_', ids), ids[0], ids[2], fields));
            }
            return result;
        }

        //处理model字符串
        private void GetModelCodes(List<string> modelCodes, string fieldValue)
        {
            List<int> indexs = new List<int>();
            char[] chars = fieldValue.ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                if (chars[i].ToString() == ".") indexs.Add(i);
            }
            for (int i = 0; i < indexs.Count(); i++)
            {
                string str1;
                if (i < indexs.Count() - 1)
                {
                    str1 = fieldValue.Substring(indexs[i] - 3, indexs[i + 1] - indexs[i]);

                    //123.123123.123123123.344123.123

                }
                else
                {
                    str1 = fieldValue.Substring(indexs[i] - 3, fieldValue.Length - (indexs[i] - 3));
                }

                var leftStr = str1.Left(3);
                var rightStr = str1.Substring(4, str1.Length - 4);
                for (int j = 0; j < rightStr.Length; j += 3)
                {
                    modelCodes.Add($"{leftStr}{rightStr.Substring(j, 3)}");
                }
            }
        }
        private HashSet<string> GetModelCodes(string fieldValue)
        {
            HashSet<string> retList = new HashSet<string>();
            if (string.IsNullOrEmpty(fieldValue))
            {
                return retList;
            }
            fieldValue = fieldValue.Replace(".", "").Replace(" ", "");
            var count = fieldValue.Length / 6;
            for (int i = 0; i < count; i++)
            {
                retList.Add(fieldValue.Substring(i * 6, 6));
            }
            return retList;
        }

        #endregion

        /// <summary>
        /// 快速找件
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public object QuickQueryParts(JObject param)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            string brandCode = param.Value<string>(ParamFields._brandCode);
            string partCodes = param.Value<string>(ParamFields._partCodes);
            string vin = param.Value<string>(ParamFields._vin);
            int selectorId = param.Value<int>(ParamFields._selectorId);
            if (!CheckQuickQueryPartsParam(brandCode, partCodes))
            {
                return ret;
            }

            IEnumerable<string> allPartCodes = GetSpcByPartCodes(partCodes);
            if (allPartCodes != null && allPartCodes.Any())
            {
                ret = base.Invoke<QuickPartResult>(CSIs.Query_QuickParts, new { partCodes = partCodes, brandCode }); ;
                //ret = QuickQueryPartsFilterByMarket(repository, ret, selectorId);
                ret = QuickQueryPartsFilterByUsage(ret, vin, selectorId);
            }
            return ret;
        }

        bool CheckQuickQueryPartsParam(string brandCode, string partCodes)
        {
            bool res = true;
            if (string.IsNullOrEmpty(brandCode) || string.IsNullOrEmpty(partCodes))
            {
                return false;
            }
            var partCodeArr = partCodes.Split(new char[] { ',' });
            if (partCodeArr.Count() > 50)
            {
                return false;
            }

            return res;
        }

        IEnumerable<string> GetSpcByPartCodes(string partCodes)
        {
            List<string> result = new List<string>();
            if (!string.IsNullOrEmpty(partCodes))
            {
                var param = partCodes.Split(new char[] { ',' });
                result.AddRange(param);

                List<string> partList = base.Invoke<string>(CSIs.Get_Spcs_By_PartCodes, new { partCodes = param });
                if (partList != null && partList.Any())
                {
                    partList.ForEach(e =>
                    {
                        if (!string.IsNullOrEmpty(e))
                        {
                            var tmpPartCodes = e.Split(new char[] { ',' });
                            result.AddRange(tmpPartCodes);
                        }
                    });
                }
            }
            return result.Distinct();
        }

        List<QuickPartResult> QuickQueryPartsFilterByUsage(List<QuickPartResult> parts, string vin, int selectorId)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            //车型下的快速找件
            if (string.IsNullOrEmpty(vin))
            {
                ret = QuickQueryPartsFilterByUsage_Model(parts, selectorId);
            }
            //vin下快速找件
            else
            {
                ret = QuickQueryPartsFilterByUsage_Vin(parts, selectorId, vin);
            }
            return ret;
        }

        List<QuickPartResult> QuickQueryPartsFilterByUsage_Vin(List<QuickPartResult> parts, int selectorId, string vin)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            //if (!string.IsNullOrEmpty(vin) && parts != null && parts.Any())
            //{
            //    List<string> partCodes = parts.Select(e => e.partCode).Distinct().ToList();
            //    List<Query_PartsResult> partUsages = repository.Invoke<Query_PartsResult>(CSIs.Query_Quick_PartUsage_For_Roewe, new { selectorId, partCodes });
            //    if (partUsages != null && partUsages.Any())
            //    {
            //        List<string> usedPartCodes = new List<string>();

            //        HashSet<string> setCodes = new HashSet<string>();
            //        dynamic vinInfo = repository.Invoke(CSIs.Query_Quick_Vin_For_Roewe, new { vin });
            //        if (vinInfo != null)
            //        {
            //            IEnumerable<dynamic> filters = repository.Invoke(CSIs.Get_Vin_Usage_Filter_For_Roewe, new { vinInfo.vinFeatureId, vinInfo.modelId });
            //            setCodes = new HashSet<string>(filters.Select(q => (string)q.ucCode));
            //        }

            //        foreach (var item in partUsages)
            //        {
            //            if (string.IsNullOrEmpty(item.featureCodes))
            //            {
            //                usedPartCodes.Add(item.partCode);
            //                continue;
            //            }
            //            var ucCodes = item.featureCodes.Split(',');

            //            var pass = false;
            //            foreach (var ucCode in ucCodes)
            //            {
            //                if (setCodes.Contains(ucCode))
            //                {
            //                    pass = true;
            //                    break;
            //                }
            //            }
            //            if (pass)
            //            {
            //                usedPartCodes.Add(item.partCode);
            //            }
            //        }

            //        if (usedPartCodes.Any())
            //        {
            //            ret = parts.Where(e => usedPartCodes.Contains(e.partCode)).ToList();
            //        }
            //    }
            //}
            return ret;
        }

        List<QuickPartResult> QuickQueryPartsFilterByUsage_Model(List<QuickPartResult> parts, int selectorId)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            //if (selectorId > 0 && parts != null && parts.Any())
            //{
            //    List<string> partCodes = parts.Select(e => e.partCode).Distinct().ToList();

            //    List<Query_PartsResult> partUsages = repository.Invoke<Query_PartsResult>(CSIs.Quick_PartUsage_By_SelectorId, new { selectorId, partCodes });
            //    if (partUsages != null && partUsages.Any())
            //    {
            //        foreach (var item in parts)
            //        {
            //            if (partUsages.FirstOrDefault(e => e.partCode == item.partCode) != null)
            //            {
            //                ret.Add(item);
            //            }
            //        }
            //    }
            //}
            return ret;
        }
    }

}


